/*
 *  Copyright 2016 http://www.kedacomframework.org
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package com.kedacom.ctsp.authz.oauth2.controller;

import com.alibaba.fastjson.JSON;
import com.kedacom.ctsp.authz.Authorize;
import com.kedacom.ctsp.authz.entity.Authentication;
import com.kedacom.ctsp.authz.exception.UnauthorizedException;
import com.kedacom.ctsp.authz.oauth2.core.GrantType;
import com.kedacom.ctsp.authz.oauth2.core.OAuth2Exception;
import com.kedacom.ctsp.authz.oauth2.core.TokenType;
import com.kedacom.ctsp.authz.oauth2.entity.AccessToken;
import com.kedacom.ctsp.authz.oauth2.entity.Client;
import com.kedacom.ctsp.authz.oauth2.service.ClientService;
import com.kedacom.ctsp.authz.oauth2.service.OAuth2GrantService;
import com.kedacom.ctsp.authz.oauth2.service.code.AuthorizationCodeRequest;
import com.kedacom.ctsp.authz.oauth2.service.code.AuthorizationCodeService;
import com.kedacom.ctsp.authz.oauth2.service.code.HttpAuthorizationCodeRequest;
import com.kedacom.ctsp.authz.oauth2.service.implicit.HttpImplicitRequest;
import com.kedacom.ctsp.authz.oauth2.service.implicit.ImplicitRequest;
import com.kedacom.ctsp.authz.oauth2.util.RedirectUrlUtil;
import com.kedacom.ctsp.authz.oauth2.vo.AuthorizationCodeVO;
import com.kedacom.ctsp.authz.oauth2.vo.ImplicitAccessTokenVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import static com.kedacom.ctsp.authz.oauth2.core.ErrorType.ILLEGAL_CLIENT_ID;
import static com.kedacom.ctsp.authz.oauth2.core.ErrorType.ILLEGAL_REDIRECT_URI;

/**
 * TODO 完成注释
 *
 * @author zhouhao
 */
@Controller
@Api(tags = "kedacom-oauth2", description = "OAuth2授权", hidden = true)
@RequestMapping("${commons.web.mappings.oauth2_authorize:authorize}")
@Authorize
@Log4j
public class OAuth2AuthorizeController {

    @Resource
    private AuthorizationCodeService authorizationCodeService;
    @Resource
    private OAuth2GrantService oAuth2GrantService;
    @Autowired
    private ClientService clientService;

    @GetMapping(params = "response_type=code")
    @ApiOperation("登录用户获取OAuth2.0授权码")
    public String requestCode(
            @RequestParam("redirect_uri") String redirectUrl,
            @RequestParam(value = "state", required = false) String state,
            @RequestParam(value = "return_uri", required = false) String returnUrl,
            HttpServletRequest request) throws UnsupportedEncodingException {

        Authentication authentication = Authentication.current().orElseThrow(UnauthorizedException::new);

        AuthorizationCodeRequest codeRequest = new HttpAuthorizationCodeRequest(
                authentication.getUser().getId(), request);
        log.info(String.format("========步骤是:%d_方法是:%s_功能是:%s,参数是:%s", 3, "OAuth2AuthorizeController.requestCode", "登录用户获取OAuth2.0授权码", JSON.toJSONString(codeRequest)));
        Client client = clientService.getClient(codeRequest.getClientId());

        if (client == null) {
            throw new OAuth2Exception(ILLEGAL_CLIENT_ID);
        }

        if (!client.getRedirectUri().equals(codeRequest.getRedirectUri())) {
            throw new OAuth2Exception(ILLEGAL_REDIRECT_URI);
        }
        String code = authorizationCodeService.create(codeRequest);

        AuthorizationCodeVO model = new AuthorizationCodeVO();
        model.setCode(code);
        model.setRedirectUri(redirectUrl);
        model.setState(state);
        model.setReturnUri(URLEncoder.encode(returnUrl, "utf-8"));
        log.info(String.format("========步骤是:%d_方法是:%s_功能是:%s,参数是:%s", 4, "OAuth2AuthorizeController.requestCode", "登录用户获取OAuth2.0授权码", model));
        return "redirect:" + RedirectUrlUtil.redirect(model);
    }


    @GetMapping(params = "response_type=token")
    @ApiOperation("implicit方式授权")
    public String authorizeByImplicit(
            @RequestParam(value = "client_id") String clientId,
            @RequestParam(value = "client_secret") String clientSecret,
            @RequestParam(value = "redirect_uri") String redirectUri,
            @RequestParam(value = "state") String state,
            @RequestParam(value = "return_uri", required = false) String returnUrl,
            HttpServletRequest request) throws UnsupportedEncodingException {

        Authentication authentication = Authentication.current().orElseThrow(UnauthorizedException::new);
        clientService.validateClient(clientId, clientSecret);
        ImplicitRequest implicitRequest = new HttpImplicitRequest(authentication.getUser().getId(), request);
        AccessToken accessToken = oAuth2GrantService.grant(GrantType.IMPLICIT, implicitRequest);

        ImplicitAccessTokenVO model = new ImplicitAccessTokenVO();
        model.setState(state);
        model.setTokenType(TokenType.TOKEN_BEARER);
        model.setAccessToken(accessToken.getAccessToken());
        model.setExpiresIn(accessToken.getExpiresIn());
        model.setRedirectUri(URLEncoder.encode(redirectUri, "utf-8"));
        model.setReturnUri(URLEncoder.encode(returnUrl, "utf-8"));
        return "redirect:" + RedirectUrlUtil.redirect(model);
    }

}
